#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <stdbool.h>
#include <dequeue.h>

#define MAX 40

char *memoria, **fitas, *entrada, word;
int *indices_parado, **indx_inicio_blocos, **count_blocos, qt_blocos=0;
bool flag_passou = false;
bool flag_passou_uma = false;
int qt_fitas;
int i, tam, j, opc;
int current_fita = -1;

float **Alocar_fitas_real (int, int);
void distribui_blocos();
void ordena_memoria(char*, int, int);

int main(void)
{
    //int i, tam, qt_fitas, j, opc;
    do
    {
        opc=0;
        system("cls");
        printf("===============================SIMULACAO-INTERCALACAO===============================\n\n");
        printf("1 -> Criar memoria\n");
        printf("2 -> Criar fitas\n");
        printf("3 -> Inserir dados no vetor de entrada\n");
        printf("4 -> Iniciar metodo de intercalacao\n");
        printf("5 -> Imprimir fitas/memoria/vetor de entrada\n");
        printf("10 -> Sair\n\n");
        printf("Opcao: ");
        fflush(stdin);
        scanf("%d", &opc);
        switch (opc)
        {
            case 1:
            {
                printf("digite o tamanho da memoria (Maximo de 40): ");
                scanf("%i", &tam);
                if (tam<0)
                {
                    printf("O tamanho da memoria deve ser maior que 0");
                }
                else
                {
                    memoria = (char*) calloc(tam+1, sizeof( char ) );
                }
                if (memoria == NULL)
                {
                    printf("Memoria nao criada!!!");
                }
                else
                {
                    printf("lista criada com sucesso!!!");
                }
                break;
            }
            case 2:
            {
                printf("digite a quantidade de fitas (Maximo de 40 fitas): ");
                scanf("%i", &qt_fitas);
                if (qt_fitas<0)
                {
                    printf("A quantidade de fitas deve ser maior que 0!!!");
                }
                else
                {
                    fitas = Alocar_fitas_real(qt_fitas, 40);
                    entrada = (char*) calloc (MAX, sizeof ( char ) );
                    posiciona_fita(qt_fitas);
                    indices_parado[current_fita]=0;
                    entrada = (char*) calloc (1, MAX*sizeof ( char ) );
                    if (entrada == NULL)
                    {
                        printf("fitas nao criada!!!");
                    }
                    else
                    {
                        printf("fitas criadas com sucesso!!!");
                    }
                }
                break;
            }
            case 3:
            {
                i = 0;
                int ind = 0;
                while(!_kbhit())//funcao bkhit le entradas do teclado
                {
                    int h;
                    for(h=0; h<tam;)//loop para distribuicao dos blocos na fita 0
                    {
                        ind = indices_parado[current_fita];
                        fflush(stdin);
                        system("cls");
                        imprime_fitas(qt_fitas);
                        imprime_memoria(tam);
                        imprime_entrada(MAX);
                        printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");

                        if(memoria[(tam-1)]==NULL && word!=13)
                        {
                            while(strlen(memoria) < tam)
                            {
                                system("cls");
                                imprime_fitas(qt_fitas);
                                imprime_memoria(tam);
                                imprime_entrada(MAX);
                                printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");
                                word = tolower(_getch());
                                if(word==13)break;
                                memoria[i] = word;
                                //memoria[i+1] = NULL;
                                i++;
                                system("cls");
                                imprime_fitas(qt_fitas);
                                imprime_memoria(tam);
                                imprime_entrada(MAX);
                                printf("\n\n----Entrada (para finalizar a entrada de dados pressione enter)----\n");
                            }
                        }

                        if(word!=13)// {
                            word = tolower(_getch());

                            if (fitas[current_fita][0]==NULL)
                            {
                                indices_parado[current_fita] = 0;
                                ordena_memoria(memoria, strlen(memoria), h);
                                move_pra_fita(h, false);
                                memoria[h] = word;
                            }
                            else
                            {
                                if (word != 13)
                                {
                                    if (memoria[h]<fitas[current_fita][ind-1])
                                    {
                                        if(h<(tam-1))
                                        {
                                            ordena_memoria(memoria, strlen(memoria), h);
                                            h++;
                                            move_pra_fita(h, false);
                                        }
                                        else
                                        {
                                            h=0;
                                            ordena_memoria(memoria, strlen(memoria), h);
                                            posiciona_fita(qt_fitas);
                                            ind = indices_parado[current_fita];
                                            if(ind != 0){
                                                move_pra_fita(h, true);
                                            }else{
                                                move_pra_fita(h, false);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        ordena_memoria(memoria, strlen(memoria), h);
                                        move_pra_fita(h, false);
                                    }
                                    memoria[h] = word;
                                }
                            }

                            if(word==13)
                            {

                                if (memoria[h]<fitas[current_fita][ind-1])
                                {
                                    if(h<(tam-1))
                                    {
                                        ordena_memoria(memoria, strlen(memoria), h);
                                        h++;
                                        move_pra_fita(h, false);
                                        memoria[h]=word;
                                        for(int sub_h=h;sub_h<strlen(memoria);sub_h++)
                                            memoria[sub_h]=memoria[sub_h+1];
                                    }
                                }


                                if(h>=(tam-1)){
                                     h=0;
                                }

                                if(h>0){

                                    ordena_memoria(memoria, strlen(memoria), h);

                                    for(;h<tam;h++)
                                    {
                                        if(memoria[h]=='\0')break;

                                        move_pra_fita(h, false);

                                        for(int sub_h=h;sub_h<strlen(memoria);sub_h++)
                                            memoria[sub_h]=memoria[sub_h+1];
                                    }
                                }


                                posiciona_fita(qt_fitas);
                                ind = indices_parado[current_fita];
                                //ordena_memoria(memoria, strlen(memoria), h);

                                bool novoBloco = true;
                                if(ind != 0 && h > 0 || fitas[current_fita][ind-1]>memoria[0]){
                                            novoBloco = true;
                                        }else{
                                            novoBloco = false;
                                        }

                                h=0;
                                ordena_memoria(memoria, strlen(memoria), h);

                                for(h=0;h<tam; h++)
                                {
                                    if(memoria[h] != NULL){
                                        move_pra_fita(h, novoBloco);
                                        memoria[h]=NULL;
                                        novoBloco = false;
                                    }
                                }

                                fflush(stdin);
                                system("cls");
                                imprime_fitas(qt_fitas);
                                imprime_memoria(tam);
                                imprime_entrada(MAX);
                                printf("\n\nPressione qualquer tecla para voltar ao menu!!!\n");
                                getch();
                                break;
                            }
                        //}
                        //ind++;
                    }
                    break;
                }
                break;
            }
            case 4:
            {
                int qtdFitasVazias =0;
                int index;
                system("cls");
                        printf("%d",qt_fitas );
                        getch();
                while(qtdFitasVazias <= (qt_fitas-1)){
                    index=0;
                    while(index < qt_fitas-1){
                        if(fitas[index][0] == NULL){
                            qtdFitasVazias++;
                        }
                        index++;
                        fitas[index][0] = NULL;
                        system("cls");
                        printf("%d",qtdFitasVazias );
                        getch();
                    }
                }
                break;
            }
            case 5:
            {
                system("cls");
                imprime_fitas(qt_fitas);
                imprime_memoria(tam);
                imprime_entrada(MAX);
                printf("\nQualquer tecla para retornar!!!\n");
                getch();
                break;
            }
        }
    }while(opc!=10);
}

float **Alocar_fitas_real (int m, int n)
{
    char **v;  /* ponteiro para a matriz */
    int   i;    /* variavel auxiliar      */

    if (m < 1 || n < 1)   /* verifica parametros recebidos */
    {
        printf ("** Erro: Parametro invalido **\n");
        return (NULL);
    }

    /* aloca as linhas da matriz */
    v =  calloc (m, sizeof(char *));	/* Um vetor de m ponteiros para floatv =  calloc (m, sizeof(char *));	/* Um vetor de m ponteiros para float */
    indices_parado =  calloc (m-1, sizeof(int *));	/* Um vetor de m ponteiros para int*/
    if (v == NULL)
    {
        printf ("** Erro: Memoria Insuficiente **");
        return (NULL);
    }

    /* aloca as colunas da matriz */
    for ( i = 0; i < m; i++ )
    {
        v[i] =  calloc (n, sizeof(char));	/* m vetores de n floats */
        if (v[i] == NULL)
        {
            printf ("** Erro: Memoria Insuficiente **");
            return (NULL);
        }
    }

    return (v); /* retorna o ponteiro para a matriz */
}

float **Liberar_fitas_real (int m, int n, char **v)
{
    int  i;  /* variavel auxiliar */

    if (v == NULL) return (NULL);
    if (m < 1 || n < 1)    /* verifica parametros recebidos */
    {
        printf ("** Erro: Parametro invalido **\n");
        return (v);
    }
    for (i=0; i<m; i++) free (v[i]); /* libera as linhas da matriz */
    free (v);      /* libera a matriz (vetor de ponteiros) */
    return (NULL); /* retorna um ponteiro nulo */
}

void imprime_fitas (int qt_fitas)
{
    int curFita, curPosicao;
    for (curFita = 0; curFita < qt_fitas; curFita++)
    {
        printf("\n\nFita %d:\n", curFita);
        for ( curPosicao = 0; curPosicao < MAX; curPosicao++)
        {
            if(fitas[curFita][curPosicao]!=NULL ){
                    if(toupper(fitas[curFita][curPosicao]) == fitas[curFita][curPosicao]){
                        printf("   -|-   [ %c ]", tolower(fitas[curFita][curPosicao]));
                    }else
                    {
                        printf("[ %c ]", fitas[curFita][curPosicao]);
                    }
            }
            else
            {
                break;
            }
        }
    }
}

void imprime_memoria (int tam)
{
    int i;
    printf("\n\nMemoria: ");
    for(i = 0; i<tam; i++)
    {
        printf("[ %c ]", memoria[i]);
    }
}

void imprime_entrada (int tam)
{
    int i;
    printf("\nVetor de entrada: ");
    for(i = 0; i<tam; i++)
    {
        if(entrada[i]==NULL)break;
        printf("%c ", entrada[i]);
    }
}

int posiciona_fita(int n_fitas)
{

    if(current_fita < n_fitas-2 && !flag_passou)
    {
            current_fita++;
            return current_fita;
    }
    else
    {
        if(!flag_passou)
        {
            if(!flag_passou_uma){
                flag_passou =true;
                flag_passou_uma = true;
            }
            current_fita =0;
            return current_fita;
        }
        else
        {
            flag_passou =false;
            current_fita =0;
            return current_fita;
        }
    }
}


void ordena_memoria(char *v, int tam, int indice)
{
    int aux, troca, j, i;
    j = tam - 1;
    do
    {
        troca = 0;
        for (i=indice; i<j; i++)
            if (v[i] > v[i+1]/* && (v[i+1] != "\0" || v[i+1] != NULL) && (v[i] != "\0" || v[i] != NULL)*/)
            {
                aux = v[i];
                v[i] = v[i + 1];
                v[i + 1] = aux;
                troca = 1;
            }
        j--;
    }
    while(troca);
}

void imprime_indices()
{
    int i =0;
    for (i=0; i<qt_fitas-1; i++)
    {
        printf("fita:%d **%d \n", i,indices_parado[i]);
    }
}
void move_pra_fita(int h, bool novoBloco)
{
    // imprime_indices();
    /*printf("indice %d \n",indices_parado[current_fita]);
    printf("fita %d \n",current_fita);
    printf("h %d \n",h);
    getch();*/
    if(novoBloco)
    {
        fitas[current_fita][indices_parado[current_fita]]=toupper(memoria[h]);
    }
    else
    {
        fitas[current_fita][indices_parado[current_fita]]=memoria[h];
    }
    indices_parado[current_fita]++;
}

void intercalacao_polifasica(){



}
